package com.camel.chart;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.camel.chart.enums.MsgTypeEnum;
import com.camel.chart.func.TcpServer;
import com.camel.chart.func.UdpClient;
import com.camel.chart.func.UdpServer;
import com.camel.chart.utils.*;
import com.camel.chart.utils.entity.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.io.File;
import java.net.*;
import java.util.*;

/**
 * @author Administrator
 */
public class MainApplication extends Application {

    private int chartIndex = 0;

    public static boolean loading = false;

    public static String fileName;

    public static long fileSize;
    //是否准备好文件接收
    public static boolean isFile;

    public ResourceBundle resourceBundle;

    public ResourceBundle getResourceBundle() {
        if(ObjectUtil.isEmpty(this.resourceBundle)) {
            FXMLLoader fXMLLoader = MainApplication.getFXMLLoader();
            this.resourceBundle = fXMLLoader.getResources();
        }
        return this.resourceBundle;
    }

    @FXML
    private ScrollPane leftScroll;

    @FXML
    public Pane chartDetail;

    @FXML
    public Text chartDetailHeader;

    @FXML
    public Button messageSend;

    @FXML
    public TextArea messageBox;

    @FXML
    public ScrollPane chartContent;



    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fXMLLoader = MainApplication.getFXMLLoader();
        this.resourceBundle = fXMLLoader.getResources();
        Parent root = fXMLLoader.load();
        Scene scene = new Scene(root, 1500, 800);

        primaryStage.setResizable(true);
        primaryStage.setTitle(resourceBundle.getString("Title"));
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.setOnCloseRequest(event -> {
            MsgUtil.getInstance().sendMsg("用户登出", MsgTypeEnum.TYPE_LOGOUT, chartContent);

        });
    }

    @FXML
    public void initialize() throws Exception {

        ApplicationConfig.getInstance().application = this;

        // 加载上次的配置
        initFriend();

        // 设置监听
        listenUDP();

        // 声明在线
        broadcastOnline();

        // 刷新用户
        refreshUsers();

        chartContent.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);

//        chartContent.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> Platform.runLater(new Runnable() {
//            @Override
//            public void run() {
//                synchronized (MainApplication.class) {
//                    if (!MainApplication.loading) {
//                        chartContent.setVvalue(1.0);
//                    } else {
//                        chartContent.setVvalue((5.0 + 20) / (chartIndex + 20));
//                        MainApplication.loading = false;
//                    }
//                }
//            }
//        }));

        chartContent.vvalueProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue.equals(0.0)) {
                loadMoreChartHistory(null);
            }
        });

        messageBox.setOnDragOver(event -> {
            Dragboard db = event.getDragboard();
            if (db.hasFiles()) {
                event.acceptTransferModes(TransferMode.COPY);
            }
        });

        messageBox.setOnDragDropped(event -> {
            Dragboard db = event.getDragboard();
            boolean success = false;
            if (db.hasFiles()) {
                success = true;
                // 处理文件
                db.getFiles().forEach(file -> dragDropEventHandler(file));
            }
            event.setDropCompleted(success);
            event.consume();
        });

        messageBox.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.ENTER) {
                sendMessage();
            }
        });
    }

    public void dragDropEventHandler(File file) {
        FileUtil.FileEntity fileEntity = new FileUtil.FileEntity();
        fileEntity.setFileId(UUID.randomUUID().toString());
        fileEntity.setFileName(file.getName());
        fileEntity.setFilePath(file.getPath());
        fileEntity.setFileSize(file.length());
        MsgUtil.getInstance().sendFileReqMsg(fileEntity, chartContent);
    }

    /**
     * 广播自己在线情况
     */
    void broadcastOnline() {
        try {
            DatagramSocket send = new DatagramSocket();
            Msg msg = new Msg();
            msg.setType(MsgTypeEnum.TYPE_LOGIN);
            new Thread(new UdpClient(send, 8888, InetAddress.getByAddress(getAroadInetAddressAsByteArray()), msg, chartContent)).start();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 监听广播
     */
    void listenUDP() {
        try {
            // 监听 8888 端口  获取  从其他端口发送过来的数据
            new Thread(new UdpServer(new DatagramSocket(8888, InetAddress.getByAddress(Objects.requireNonNull(IPUtils.getInetAddress()))), this)).start();
            new Thread(new TcpServer(51818, this)).start();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (NullPointerException e) {

        }
    }

    /**
     * 获取广播地址
     *
     * @return
     */
    public byte[] getAroadInetAddressAsByteArray() {
        try {
            return ApplicationConfig.getInstance().getChartNetWorkInterface().getBroadCastAddressAsByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取本机IP地址
     *
     * @return
     */

    public void initFriend() throws Exception {
        chartContent.setPadding(new Insets(30, 0, 30, 0));
        // 设置网卡
        ChartNetWorkInterface workInterface = (ChartNetWorkInterface) SerializeUtil.deserializeObject(CommonConstants.DEFAULT_CONFIG_NETWORK_INTERFACE_SERIALIZABLE_FILE);

        if (!ObjectUtil.isEmpty(workInterface)) {
            ApplicationConfig.getInstance().setChartNetWorkInterface(workInterface);
        }
        Vector<NetDevice> devices = ApplicationConfig.getInstance().deserializeDevices();

        if (!CollectionUtil.isEmpty(devices)) {
            ApplicationConfig.getInstance().devices = devices;
        }
    }

    public static FXMLLoader getFXMLLoader() {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("locale.IamFxChart");
        URL url = Object.class.getResource("/com/camel/iamFxTools/fxmlView/chart/index.fxml");
        FXMLLoader fXMLLoader = new FXMLLoader(url, resourceBundle);
        return fXMLLoader;
    }

    public static void main(String[] args) {
        try {
            launch(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @FXML
    private void selectNetInterface() throws Exception {
        List<ChartNetWorkInterface> choices = NetInterfaceUtil.getNetInterfaces();
        ChoiceDialog<ChartNetWorkInterface> dialog = new ChoiceDialog<>(null, choices);
        dialog.setTitle(resourceBundle.getString("SelectNetworkInterface"));
        Optional<ChartNetWorkInterface> result = dialog.showAndWait();
        if (result.isPresent()) {
            ApplicationConfig.getInstance().setChartNetWorkInterface(result.get());
            NetDevice.myInetAddress = result.get().getInetAddress();
            // 声明自己在线
            broadcastOnline();
            ApplicationConfig.getInstance().serilizeAll();
        }
    }

    @FXML
    private void refreshUsers() {
        refreshUserList();
    }

    /**
     * 发送消息
     */
    @FXML
    public void sendMessage() {
        String text = messageBox.getText();
        if (StrUtil.isBlank(text)) {
            return;
        }
        //todo sendFile逻辑
        FileUtil.FileEntity fileEntity = new FileUtil.FileEntity();
        fileEntity.setFileId(UUID.randomUUID().toString());
        MsgUtil.getInstance().sendTcpMsg(text, MsgTypeEnum.TYPE_TEXT_MSG, chartContent);
        messageBox.clear();
    }


    /**
     * 刷新历史聊天记录
     */
    public void refreshChartHistory(String inetAddress) {
        this.chartIndex = 0;
        Vector<Msg> msgs = SerializeUtil.deserializeFileToObjs(inetAddress + ".txt", "history", this.chartIndex, 20);
        ChartHistory.getInstance().getMsges().put(inetAddress, msgs);
        refreshChartHistoryUI(inetAddress);
    }


    /**
     * 加载更多历史记录
     */
    public void loadMoreChartHistory(String inetAddress) {
        synchronized (MainApplication.class) {
            MainApplication.loading = true;
            inetAddress = StrUtil.isBlank(inetAddress) ? ApplicationConfig.getInstance().currentDevice.getInetAddress() : inetAddress;
            this.chartIndex += 20;
            Vector<Msg> results = SerializeUtil.deserializeFileToObjs(inetAddress + ".txt", "history", this.chartIndex, 20);
            Collection<Msg> msgs = ChartHistory.getInstance().getMsges().get(inetAddress);
            if (CollectionUtil.isEmpty(results)) {
                this.chartIndex -= 20;
                return;
            }
            if (CollectionUtil.isEmpty(msgs)) {
                ChartHistory.getInstance().getMsges().put(inetAddress, results);
            } else {
                results.addAll(msgs);
                ChartHistory.getInstance().getMsges().put(inetAddress, results);
            }
            refreshChartHistoryUI(inetAddress);
        }
    }


    /**
     * 刷新历史聊天记录
     */
    public void refreshChartHistoryUI(String inetAddress) {
        chartContent.setContent(null);
        chartContent.setVvalue(1.0);
        Vector<Msg> msgs = (Vector) ChartHistory.getInstance().getMsges().get(inetAddress);
        if (CollectionUtil.isEmpty(msgs)) {
            return;
        }
        for (Msg msg : msgs) {
            MsgUtil.getInstance().addMsgUI(chartContent, msg);
        }
    }

    public void refreshUserList() {
        VBox vBox = new VBox();
        for (NetDevice device : ApplicationConfig.getInstance().getDevices()) {
            Pane pane = new Pane();
            pane.setMinWidth(leftScroll.getMinWidth());
            pane.setMaxWidth(leftScroll.getMaxWidth());

            ImageView imageView = new ImageView();
            Image image = new Image(CommonConstants.DEFAULT_PROFILE_IMAGE);
            imageView.setImage(image);
            imageView.setFitWidth(100);
            imageView.setFitHeight(100);
            // IP地址显示
            Text text = new Text();
            text.setText(device.getInetAddress());
            text.setX(120);
            text.setY(100);

            Text textRemark = new Text();
            textRemark.setText(!ObjectUtil.isEmpty(device.getRemark()) ? device.getRemark() : device.isMyDevice() ? getResourceBundle().getString("Own") : getResourceBundle().getString("Stranger"));
            textRemark.setX(120);
            textRemark.setY(30);
            textRemark.setFont(new Font(20));

            pane.getChildren().add(imageView);
            pane.getChildren().add(text);
            pane.getChildren().add(textRemark);
            pane.setPrefWidth(280.0);
            pane.setPrefHeight(114.0);
            pane.setStyle("-fx-padding: 0 0 0 10");

            pane.onMouseEnteredProperty().set(event -> {
                Pane target = (Pane) event.getTarget();
                target.setBackground(new Background(new BackgroundFill(Color.LIGHTGRAY, CornerRadii.EMPTY, Insets.EMPTY)));
            });

            pane.onMouseExitedProperty().set(event -> {
                Pane target = (Pane) event.getTarget();
                target.setBackground(null);
            });

            pane.onMouseClickedProperty().set(event -> {
//                if (device.isMyDevice()) {
//                    return;
//                }
                ApplicationConfig.getInstance().currentDevice = device;
                chartDetail.setVisible(true);
                chartDetailHeader.setText(device.getInetAddress() + "(" + (!ObjectUtil.isEmpty(device.getRemark()) ? device.getRemark() : device.isMyDevice() ? resourceBundle.getString("Own") : resourceBundle.getString("Stranger")) + ")");
                // 刷新聊天记录
                refreshChartHistory(device.getInetAddress());
            });
            ContextMenu contextMenu = new ContextMenu();
            MenuItem menuItem1 = new MenuItem(getResourceBundle().getString("Remark"));
            contextMenu.getItems().addAll(menuItem1);

            menuItem1.setOnAction(event -> {
                TextInputDialog textInputDialog = new TextInputDialog();
                textInputDialog.setTitle(getResourceBundle().getString("Remark"));
                textInputDialog.setHeaderText(getResourceBundle().getString("RemarkOthores"));
                textInputDialog.setContentText(getResourceBundle().getString("Remark"));
                Button btnOk = (Button) textInputDialog.getDialogPane().lookupButton(ButtonType.OK);
                btnOk.setOnAction(event1 -> {
                    //输入框中的文本
                    String text1 = textInputDialog.getEditor().getText();
                    NetDevice currentDevice = ApplicationConfig.getInstance().getCurrentDevice();
                    currentDevice.setRemark(text1);
                    ApplicationConfig.getInstance().setCurrentDevice(currentDevice);
                    try {
                        refreshUsers();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });
                textInputDialog.show();
            });

            pane.setOnContextMenuRequested(event -> {
                contextMenu.show(pane, event.getScreenX(), event.getScreenY());
                // 阻止默认的右键菜单显示
                event.consume();
            });

            vBox.getChildren().add(pane);
        }
        leftScroll.setContent(vBox);
    }

}
